home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 July: Mac OS SDK / Dev.CD Jul 97 SDK1.toast / Development Kits (Disc 1) / QuickDraw GX / Programming Stuff / Sample Code / Printing Samples / Printer Drivers… / LaserWriterIIsc (New GX v1.1) / SCPrinterStatus.c < prev    next >
Encoding:
Text File  |  1996-06-15  |  28.1 KB  |  850 lines  |  [TEXT/MPS ]

  1. /*---------------------------------------------------------------------------
  2. FILENAME
  3.     SCPrinterStatus.c
  4.  
  5. DESCRIPTION
  6.     This file contains the routines which manage checking the status of the 
  7.     SC printer and alerting the user (as needed) to problems that might arise.
  8.         
  9. COPYRIGHT
  10.     Copyright Apple Computer, Inc. 1989-1996
  11.     All rights reserved. 
  12.     
  13. MODIFICATION HISTORY
  14.      6/14/96 - cn  - Updated to support Universal Interfaces 2.1.
  15.  
  16. INTERFACE ROUTINES:
  17.     SetPrinterProblemStatResIndex
  18.     SetPrinterProblemStatResID
  19.     FindPrinterProblem
  20.     ResolvePrinterProblem
  21.  
  22. --------------------------------------------------------------------------- */
  23.  
  24. // Include the standard Mac header files 
  25. #include "MacIncludes.h"
  26.  
  27. // Include the new QuickDraw GX graphics header files 
  28. #include <GXGraphics.h>
  29. #include <GraphicsLibraries.h>
  30. #include <GXMath.h>
  31.  
  32. // Include the required Printing Manager header files 
  33. #include <GXPrinting.h>
  34. #include <GXPrinterDrivers.h>
  35. #include <Collections.h>
  36. #include <GXMessages.h>
  37.  
  38. #include <GXExceptions.h>
  39.  
  40. // Include the internal driver constants and types used by this module 
  41. #include "LaserSCResources.h"
  42. #include "LaserSCIntf.h"
  43. #include "SCPrinterStatus.h"
  44.  
  45.  
  46. /***************************************************************************************
  47. *                                         INTERNAL ROUTINES                                                     *
  48. ***************************************************************************************/                        
  49.  
  50. /****************************************************************************************
  51.  
  52.                             WaitForABit
  53.  
  54.                             
  55.     function:
  56.                 This routine is called to pause for a small amount of time and
  57.                 give up idle time to the foreground.
  58.                 
  59.     parameters:    
  60.                 None
  61.     returns:
  62.                 None
  63.     
  64. ****************************************************************************************/
  65. void WaitForABit(void)
  66. {
  67.     long    nextQuery = TickCount() + kQueryRate;
  68.     while (nextQuery > TickCount())
  69.         (void)GXJobIdle();
  70. }
  71. /* WaitForABit */
  72.  
  73. /****************************************************************************************
  74.  
  75.                             CheckEngineStatus1Bits
  76.  
  77.                             
  78.     function:
  79.                 This routine is called to examine the Engine Status 1 Bits in the status
  80.                 data returned from the printer.  The routine examines these bits to 
  81.                 determine if any of the following problems exists on the printer:
  82.  
  83.                                 Fixing assembly has malfunctioned
  84.                                 Laser has malfunctioned
  85.                                 Polygon motor has malfunctioned
  86.                                 Serial communications have malfunctioned
  87.                                 Some other hardware problem has occurred
  88.  
  89.                 If one of these problems is encountered, the problemStatResIndex parameter
  90.                 returns an index into a 'stat' resource of the status that reflects the 
  91.                 printer's current status. 
  92.                 
  93.     parameters:    
  94.                 pSenseData                Printer status info. received from the printer
  95.                 problemStatResIndex    returns the 'stat' index of the printer's current error
  96.                                             status if an error was encountered
  97.     returns:
  98.                 None
  99.     
  100. ****************************************************************************************/
  101. void CheckEngineStatus1Bits(SCSenseDataPtr pSenseData, short *problemStatResIndex)
  102. {
  103.     if ( FixingMalfunction(pSenseData) )
  104.         *problemStatResIndex = kBadPrintFixStatIdx;
  105.     else
  106.     if ( LaserMalfunction(pSenseData) )
  107.         *problemStatResIndex = kBadLaserStatIdx;
  108.     else
  109.     if ( PolyMalfunction(pSenseData) )
  110.         *problemStatResIndex = kBadPolyMotorStatIdx;
  111.     else
  112.     if ( SerialMalfunction(pSenseData) )
  113.         *problemStatResIndex = kBadSerialStatIdx;
  114.     else
  115.         *problemStatResIndex = kGenericBadHdwareStatIdx;
  116. }
  117. /* CheckEngineStatus1Bits */
  118.  
  119.  
  120. /****************************************************************************************
  121.  
  122.                             CheckEngineStatus0Bits
  123.  
  124.                             
  125.     function:    
  126.                 This routine is called to examine the Engine Status 0 Bits in the status
  127.                 data returned from the printer.  The routine examines these bits to 
  128.                 determine if any of the following problems exists on the printer:
  129.  
  130.                                 No toner cartridge/improperly installed
  131.                                 No paper tray/manual feed and no paper in printer
  132.                                 No paper cartridge/improperly installed
  133.                                 Paper jam
  134.                                 Upper door of printer is open
  135.                                 Test printing is underway
  136.                                 Fixing unit is being heated
  137.  
  138.                 If one of these problems is encountered, the problemStatResIndex parameter
  139.                 returns an index into a 'stat' resource of the status that reflects the 
  140.                 printer's current status. 
  141.                 
  142.     parameters:    
  143.                 pSenseData                Printer status info. received from the printer
  144.                 problemStatResIndex    returns the 'stat' index of the printer's current error
  145.                                             status if an error was encountered
  146.     returns:
  147.                 None
  148.     
  149. ****************************************************************************************/
  150. void CheckEngineStatus0Bits(SCSenseDataPtr pSenseData, short *problemStatResIndex)
  151. {
  152.     if ( NoToner(pSenseData) )
  153.         *problemStatResIndex = kBadTonerCartridgeStatIdx;
  154.     else
  155.     if ( NoPaperTray(pSenseData) )
  156.         *problemStatResIndex = kBadPaperCartridgeStatIdx;
  157.     else
  158.     if ( NoPaper(pSenseData) )
  159.         *problemStatResIndex = kOutOfPaperStatIdx;
  160.     else
  161.     if ( PaperJam(pSenseData) )
  162.         *problemStatResIndex = kPaperJamStatIdx;
  163.     else
  164.     if ( DoorOpen(pSenseData) )
  165.         *problemStatResIndex = kOpenDoorStatIdx;
  166.     else
  167.     if ( TestPrint(pSenseData) )
  168.         *problemStatResIndex = kPrintTestStatIdx;
  169.     else
  170.     if ( HeatingFixUnit(pSenseData) )
  171.         *problemStatResIndex = kHeatFixingUnitStatIdx;
  172. }
  173. /* CheckEngineStatus0Bits */
  174.  
  175.  
  176. /****************************************************************************************
  177.  
  178.                             SetStatusIndex
  179.  
  180.                             
  181.     function:
  182.                 This routine is called to initialize the statResId and statResIndex fields
  183.                 in the status record referenced by pStatus.  If the dontAlert parameter
  184.                 is true, the we make sure that only informationalStatus 'stat' resources 
  185.                 will be referenced by pStatus.
  186.                 
  187.     parameters:                
  188.                 pStatus                Status record used to alert the user to printer problems
  189.                 currentProblem        the 'stat' ID and res index of the printer's current status
  190.                 manualFeed            T => doing manual feed job; F => doing auto-feed
  191.                 dontAlert            T => we don't want to set the status record's statResId and
  192.                                         statResIndex to a value which would cause the PFE to display
  193.                                         an alert dialog to the user.  When true, we make sure only
  194.                                         informationalStatus 'stat' resources will be referenced by
  195.                                         pStatus.
  196.                 
  197.     returns:
  198.                 None
  199.                 
  200. ****************************************************************************************/
  201. void SetStatusIndex( gxStatusRecord         *pStatus, 
  202.                             long                     printerProblem, 
  203.                             Boolean                 manualFeed,
  204.                             Boolean                dontAlert)
  205. {
  206.     short        whichStatResID;
  207.     short        whichStatResIndex;
  208.     
  209.     // Extract the statResID and statResIndex values from the printerProblem parameter
  210.  
  211.     whichStatResID = GetStatResID(printerProblem);
  212.     whichStatResIndex = GetStatResIndex(printerProblem);
  213.     
  214.     // The normal settings of statResID and statResIndex are just the values in printerProblem
  215.     
  216.     pStatus->statResId         = whichStatResID;
  217.     pStatus->statResIndex     = whichStatResIndex;
  218.     
  219.     // Do we need to override the normal settings because we want to suppress an alert or
  220.     // use an alert that's already provided by the Printing Manager?
  221.     
  222.     if (whichStatResID == kTransmissionStatID)
  223.     {
  224.         switch (whichStatResIndex)
  225.         {
  226.             case kOutOfPaperStatIdx:
  227.                 if (dontAlert)    // T => Don't cause alert to be displayed
  228.                 {
  229.                     pStatus->statResIndex = kWaitingForPaperStatIdx;
  230.                 }
  231.                 else    // T => We want alert to be displayed; use system supplied alert
  232.                 {
  233.                     pStatus->statResId = gxUnivAlertStatusResourceId;
  234.                     pStatus->statResIndex = (manualFeed) ? gxUnivManualFeedIndex : gxUnivOutOfPaperIndex;
  235.                 }
  236.                 break;
  237.  
  238.             case kPaperJamStatIdx:
  239.                 if (!dontAlert)    // T => We want alert to be displayed; use system supplied alert
  240.                 {
  241.                     pStatus->statResId = gxUnivAlertStatusResourceId;
  242.                     pStatus->statResIndex = gxUnivPaperJamIndex;
  243.                 }
  244.                 break;
  245.             
  246.             case kBadPaperCartridgeStatIdx:
  247.                 if (!dontAlert)    // T => We want alert to be displayed; use system supplied alert
  248.                 {
  249.                     pStatus->statResId = gxUnivAlertStatusResourceId;
  250.                     pStatus->statResIndex = gxUnivNoPaperTrayIndex;
  251.                 }
  252.                 break;
  253.             
  254.             case kOpenDoorStatIdx:
  255.                 if (dontAlert)    // T => We want alert to be displayed; use our alernative non-alert status
  256.                 {
  257.                     pStatus->statResIndex = kOpenDoorNoAlertStatIdx;
  258.                 }
  259.                 break;
  260.             
  261.             case kBadTonerCartridgeStatIdx:
  262.                 if (dontAlert)    // T => We want alert to be displayed; use our alernative non-alert status
  263.                 {
  264.                     pStatus->statResIndex = kBadTonerCartridgeNoAlertStatIdx;
  265.                 }
  266.                 break;
  267.         }
  268.     }
  269. }
  270. /* SetStatusIndex */
  271.  
  272.  
  273. /****************************************************************************************
  274.  
  275.                             SetStatusBuffer
  276.  
  277.                             
  278.     function:
  279.                 This routine is called to initialize the contents of the status buffer
  280.                 in the status record referenced by pStatus.  If we're doing a manual feed
  281.                 job and the printer is out of paper, then we set the buffer area to be an
  282.                 appropriately initialized ManualFeedRecord structure. If it's not manual feed,
  283.                 but the printer is out of paper, then we set buffer area to be a structure of
  284.                 size outOfPaperStatusBufferSize.  
  285.                 
  286.     parameters:                
  287.                 pStatus                Status record used to alert the user to printer problems
  288.                 currentProblem        the 'stat' ID and res index of the printer's current status
  289.                 manualFeed            T => doing manual feed job; F => doing auto-feed
  290.                 thePaperType        the paper type of the paper that should be loaded into the printer
  291.                 
  292.     returns:
  293.                 None
  294.     
  295. ****************************************************************************************/
  296. void SetStatusBuffer(gxStatusRecord        *pStatus, 
  297.                             long                     printerProblem, 
  298.                             Boolean                 manualFeed,
  299.                             gxPaperType            thePaperType)
  300. {
  301.     // Determine what info needs to be added to the status record's buffer area
  302.     
  303.     if ( GetStatResIndex(printerProblem) == kOutOfPaperStatIdx )
  304.     {
  305.         if (manualFeed)    // T => Fill in the ManualFeedRecord structure with the appropriate paper type info.
  306.         {
  307.             gxManualFeedRecord    *mfeedInfo;
  308.  
  309.             mfeedInfo = (gxManualFeedRecord *) &pStatus->statusBuffer;
  310.             mfeedInfo->canAutoFeed = true;
  311.             GXGetPaperTypeName(thePaperType, mfeedInfo->paperTypeName);
  312.         }
  313.         else    //    T => Fill in the OutOfPaperRecord structure with the appropriate info.
  314.         {
  315.             gxOutOfPaperRecord    *outOfPaperInfo;
  316.  
  317.             outOfPaperInfo = (gxOutOfPaperRecord *) &pStatus->statusBuffer;
  318.             GXGetPaperTypeName(thePaperType, outOfPaperInfo->paperTypeName);
  319.         }
  320.     }
  321.     // else - For all other errors, the status buffer area will contain a univStatusBuffer structure
  322. }
  323. /* SetStatusBuffer */
  324.  
  325.  
  326. /****************************************************************************************
  327.  
  328.                             ClearStatus
  329.  
  330.                             
  331.     function:
  332.                 This routine is called to tell the Printing Finder Extension (PFE) to dismiss the
  333.                 alert we had displayed.  It signals the PFE to dismiss the alert by updating
  334.                 the device status to "ready".  Anytime the PFE receives a ready status, it
  335.                 automatically dismisses the dialog.
  336.                 
  337.     parameters:    
  338.                 pStatus        Status record to use in call to AlertTheUser
  339.                 
  340.     returns:
  341.                 OSErr
  342.     
  343. ****************************************************************************************/
  344. OSErr ClearStatus(gxStatusRecord     *pStatus)
  345. {
  346.     OSErr        anErr;
  347.     short        saveResult = pStatus->dialogResult;
  348.     
  349.     // So that the PFE highlights the ok button before dismissing the dialog, set the
  350.     // dialog result to "ok".
  351.     pStatus->dialogResult = ok;
  352.     
  353.     pStatus->statusOwner     = 'univ';
  354.     pStatus->statResId      =    gxUnivAlertStatusResourceId;
  355.     pStatus->statResIndex =    gxUnivPrinterReadyIndex;
  356.     
  357.     // Tell the PFE to remove the alert
  358.     anErr = GXAlertTheUser(pStatus);
  359.     
  360.     // Restore the previous dialog result
  361.     pStatus->dialogResult = saveResult;
  362.  
  363.     return(anErr);
  364. }
  365. /* ClearStatus */
  366.  
  367.  
  368. /****************************************************************************************
  369.  
  370.                             CheckPrinter
  371.  
  372.                             
  373.     function:
  374.                 This routine queries the printer to determine its current status.  It returns,
  375.                 in the currentProblem parameter, a resource ID and res index into a 'stat' 
  376.                 resource of the status that reflects the printer's currentstatus.  The high 
  377.                 word of currentProblem contains the 'stat' resource ID of the 'stat' resource 
  378.                 that indicates the current printer problem, and the low word contains the 
  379.                 index within the 'stat' resource of the specific printer problem.
  380.                 
  381.     parameters:    
  382.                 pStatus                Status record used for alerting the user to the printer problem
  383.                 currentProblem        returns the 'stat' ID and res index of the printer's current status
  384.                 abortPrinting        returns true if printer problem is fatal; false otherwise
  385.                 
  386.     returns:
  387.                 OSErr
  388.     
  389. ****************************************************************************************/
  390.  
  391. OSErr CheckPrinter(    gxStatusRecord         *pStatus,
  392.                             long                    *currentProblem,
  393.                             Boolean                *abortPrinting)
  394. {
  395.     OSErr        anErr;
  396.     short        printerStatus;
  397.     long        oldProblem;
  398.  
  399.     *abortPrinting = false;
  400.     
  401.     // Remember the state of the printer from the last time we statused it
  402.     oldProblem = *currentProblem;
  403.  
  404.     // Issue a "Test Unit Ready" command to the printer so that we can get the latest
  405.     // printer status info. when we query it (via a call to FindPrinterProblem).
  406.     
  407.     anErr = LaserSC_GetDeviceStatus(&printerStatus);
  408.     if (anErr == noErr)
  409.     {
  410.         // Is the printer still not ready?
  411.         if (printerStatus != kGoodCondition)
  412.         {
  413.             // Status the printer to determine its current error condition state
  414.             anErr = FindPrinterProblem(currentProblem, abortPrinting);
  415.             if (anErr == noErr)
  416.             {
  417.                 // If we've encountered a change in status or the printer is now suffering
  418.                 // a fatal error (e.g. hardware problem), then dump the current status alert
  419.                 // and return the new status
  420.                 
  421.                 if ( (oldProblem != *currentProblem) || *abortPrinting )
  422.                 {
  423.                     // Tell the Printing Finder Extension to dismiss the current alert
  424.                     anErr = ClearStatus(pStatus);
  425.                 }
  426.                 // else - no change in the status and it's not a fatal error
  427.             }
  428.             // else - can't status the printer
  429.         }
  430.         else    //    T => The printer is now ready
  431.             *currentProblem = kNoPrinterProblem;
  432.     }
  433.     // else - can't issue a "Test Unit Ready" command to the printer
  434.     
  435.     check(anErr == noErr);
  436.     return(anErr);
  437. }
  438. /* CheckPrinter */
  439.  
  440.  
  441. /***************************************************************************************
  442. *                                         INTERFACE ROUTINES                                                     *
  443. ***************************************************************************************/                        
  444.  
  445. /****************************************************************************************
  446.  
  447.                             SetPrinterProblemStatResIndex
  448.  
  449.                             
  450.     function:
  451.                 This is a utility routine for stuffing a 'stat' resource index into the 
  452.                 low word of a printer problem long word variable.  The high word of a printer
  453.                 problem variable contains the 'stat' resource ID of the 'stat' resource that
  454.                 indicates the current printer problem, and the low word contains the 
  455.                 index within the 'stat' resource of the specific printer problem.
  456.                 
  457.     parameters:                
  458.                 printerProblem        returns long word with statResIndex in the lower word
  459.                 statResIndex        'stat' resource index value to stuff into printerProblem
  460.  
  461.     returns:
  462.                 None
  463.     
  464. ****************************************************************************************/
  465. void SetPrinterProblemStatResIndex(short statResIndex, long *printerProblem)
  466. {
  467.     short    *pShort;
  468.     
  469.     pShort = ((short *) printerProblem) + 1;
  470.     *pShort = statResIndex;
  471. }
  472. /* SetPrinterProblemStatResIndex */
  473.  
  474.  
  475. /****************************************************************************************
  476.  
  477.                             SetPrinterProblemStatResID
  478.  
  479.                             
  480.     function:
  481.                 This is a utility routine for stuffing a 'stat' resource ID into the 
  482.                 high word of a printer problem long word variable.  The high word of a printer
  483.                 problem variable contains the 'stat' resource ID of the 'stat' resource that
  484.                 indicates the current printer problem, and the low word contains the 
  485.                 index within the 'stat' resource of the specific printer problem.
  486.                 
  487.     parameters:                
  488.                 printerProblem        returns long word with statResID in the high word
  489.                 statResID            'stat' resource ID value to stuff into printerProblem
  490.  
  491.     returns:
  492.                 None
  493.     
  494. ****************************************************************************************/
  495. void SetPrinterProblemStatResID(short statResID, long *printerProblem)
  496. {
  497.     short    *pShort;
  498.     
  499.     pShort = (short *) printerProblem;
  500.     *pShort = statResID;
  501. }
  502. /* SetPrinterProblemStatResID */
  503.  
  504.  
  505. /****************************************************************************************
  506.  
  507.                             FindPrinterProblem
  508.  
  509.                             
  510.     function:
  511.                 This routine is called when the driver has discovered that the LaserWriter SC
  512.                 is no longer ready.  It calls this routine to determine the reason why the
  513.                 printer is not ready.  This routine queries the printer to get the latest
  514.                 "sense data" from the printer.  It then returns a resource ID and res index 
  515.                 into a 'stat' resource of the status that reflects the printer's current 
  516.                 status.  This index is returned in the printerProblem parameter.  The high 
  517.                 word of printerProblem contains the 'stat' resource ID of the 'stat' resource 
  518.                 that indicates the current printer problem, and the low word contains the 
  519.                 index within the 'stat' resource of the specific printer problem.
  520.                 
  521.                 If the abortPrinting error is non-nil, then this routine will set it to true if 
  522.                 the error state encountered is one for which we abort printing.
  523.                 
  524.     parameters:                
  525.                 printerProblem        returns the 'stat' ID and res index of the printer's current status
  526.                 abortPrinting        if non-nil, sets to true if printer status causes printing to abort
  527.  
  528.     returns:
  529.                 OSErr
  530.     
  531. ****************************************************************************************/
  532. OSErr FindPrinterProblem(long *printerProblem,  Boolean *abortPrinting)
  533. {
  534.     OSErr                anErr;
  535.     SCSenseData     senseData;
  536.     short                problemStatResID = kNoPrinterProblem;
  537.     short                problemStatResIndex = kNoPrinterProblem;
  538.  
  539.     if (abortPrinting != nil)    // Pointer specified so initialize it 
  540.         *abortPrinting = false;
  541.  
  542.     // Get the latest status information from the printer 
  543.     anErr = LaserSC_GetSenseData(&senseData);
  544.     
  545.     if (anErr == noErr)
  546.     {
  547.         // Is the printer out of paper? 
  548.         if ( (senseData.senseKey & kEndOfMedium) == kEndOfMedium )
  549.         {
  550.             problemStatResID = kTransmissionStatID;
  551.             problemStatResIndex = kOutOfPaperStatIdx;
  552.         }
  553.         else
  554.         {
  555.             // What sort of error did we encounter? 
  556.             switch ( SenseKey(senseData) )
  557.             {
  558.                 case kNotReady:
  559.                     CheckEngineStatus0Bits(&senseData, &problemStatResIndex);
  560.                     
  561.                     if (problemStatResIndex != kNoPrinterProblem)
  562.                         problemStatResID = kTransmissionStatID;
  563.                     break;
  564.                     
  565.                 case kMediumError:
  566.                     problemStatResID = kTransmissionStatID;
  567.                     problemStatResIndex = kPaperJamStatIdx;
  568.                     break;
  569.                 
  570.                 case kHardwareError:
  571.                     CheckEngineStatus1Bits(&senseData, &problemStatResIndex);
  572.                     
  573.                     if (problemStatResIndex != kNoPrinterProblem)
  574.                         problemStatResID = kEngineStatusStatID;
  575.  
  576.                     if (abortPrinting != nil)    // Pointer specified so set it 
  577.                         *abortPrinting = true;
  578.                     break;
  579.  
  580.                 case kIllegalRequest:
  581.                     check(0);                // Illegal command - should never happen in debugged software 
  582.                     break;
  583.                 
  584.                 case kUnitAttention:
  585.                     // Check the controller status bits for a specific error. If none, flag that the 
  586.                     // printer reset itself (because it did). 
  587.                     
  588.                     if ( (senseData.controlStatus & kRamFailMask) == kRamFailMask )
  589.                     {
  590.                         problemStatResID = kEngineStatusStatID;
  591.                         problemStatResIndex = kDRamFailureStatIdx;
  592.  
  593.                         if (abortPrinting != nil)    // Pointer specified so set it 
  594.                             *abortPrinting = true;
  595.                     }
  596.                     else
  597.                     if ( (senseData.controlStatus & kEngineFailMask) == kEngineFailMask )
  598.                     {
  599.                         problemStatResID = kEngineStatusStatID;
  600.                         problemStatResIndex = kLaserInitFailureStatIdx;
  601.  
  602.                         if (abortPrinting != nil)    // Pointer specified so set it 
  603.                             *abortPrinting = true;
  604.                     }
  605.                     break;
  606.     
  607.             } // switch 
  608.         }
  609.     }
  610.  
  611.     // Update the printerProblem parameter with the proper status indicators 
  612.     
  613.     SetPrinterProblemStatResIndex(problemStatResIndex, printerProblem);
  614.     SetPrinterProblemStatResID(problemStatResID, printerProblem);
  615.     
  616.     return(anErr);
  617. }
  618. /* FindPrinterProblem */
  619.  
  620.  
  621. /****************************************************************************************
  622.  
  623.                             ResolvePrinterProblem
  624.  
  625.                             
  626.     function:
  627.                 This routine is called to alert the user to a problem with the printer.  The
  628.                 problem may be one the user can resolve (e.g. out of paper) or one which
  629.                 cannot be resolved easily (e.g. hardware problem).  For the user correctable
  630.                 problems, the user is alerted to the problem and can either fix the problem
  631.                 and continue the print job, or cancel the print job.  In the case of the
  632.                 non-resolvable problems, the user is only given the choice of aborting the
  633.                 print job.  Also, if a fatal error has occurred, we abort the print job.
  634.                 
  635.                 The routine uses the AlertTheUser Printing Manager call to display the 
  636.                 alerts to the user.  Whenever possible, we try to use a system defined
  637.                 alert (e.g. manual feed) as opposed to one provided by this driver.  An
  638.                 alert is displayed until all of the printer's problems have been resolved
  639.                 or the user aborted printing.
  640.                 
  641.     parameters:    
  642.                 printerProblem        high word contains 'stat' res ID corresponding to problem
  643.                                         low word contains 'stat' res index corresponding to problem
  644.                 manualFeed            T => doing manual feed job; F => doing auto-feed job
  645.                 thePaperType        the paper type for the paper that should be placed into
  646.                                         the printer for manual feed jobs; nil if not manual feed
  647.                 dialogResult        result (item hit) returned from the dialog when it was dismissed
  648.                 
  649.     returns:
  650.                 OSErr
  651.     
  652. ****************************************************************************************/
  653. OSErr ResolvePrinterProblem(     long             printerProblem, 
  654.                                         Boolean         manualFeed,
  655.                                         gxPaperType    thePaperType,
  656.                                         short            *dialogResult)
  657. {
  658.  
  659.     OSErr                    anErr = noErr;
  660.     OSErr                    anErr2;
  661.     gxStatusRecord        *pStatus;
  662.     gxJob                    theJob = GXGetJob();
  663.     Boolean                abortPrinting = false;
  664.     long                    oldProblem;
  665.     long                    maxStatusBuffSz;
  666.     
  667.     // Make sure we only display an alert if there has been an error
  668.     require(printerProblem != kNoPrinterProblem, NoPrinterProblem);
  669.     
  670.     // Allocate a status record large enough to handle status with the largest buffer size. 
  671.     // Currently the largest record is the max. of the univStatusBuffer, ManualFeedRecord, and OutOfPaperRecord structures. 
  672.  
  673.     maxStatusBuffSz = gxOutOfPaperStatusBufferSize;
  674.                 
  675.     pStatus = (gxStatusRecord *) NewPtrClear(sizeof(gxStatusRecord) + maxStatusBuffSz);
  676.     anErr = MemError();
  677.     require(anErr == noErr, NewPtrClear);
  678.  
  679.     // Initialize the misc. fields within the status record 
  680.     pStatus->bufferLen = maxStatusBuffSz;
  681.     pStatus->statusOwner     = 'univ';
  682.     
  683.     // Now we loop with an alert displayed until all the problems are resolved, the
  684.     // user has aborted the print job, or a fatal error has occurred.
  685.     do
  686.     {
  687.         // Initialize the status record's statResID and statResIndex fields based upon the error encountered
  688.         SetStatusIndex(pStatus, printerProblem, manualFeed, false);
  689.         
  690.         // Initialize the contents of the status record buffer based upon the error encountered
  691.         SetStatusBuffer(pStatus, printerProblem, manualFeed, thePaperType);
  692.         
  693.         // Make sure the dialogResult has been reset from some previously displayed dialog (if any) 
  694.         pStatus->dialogResult = 0;
  695.         
  696.         // Display the initial error alert and see if the problem resolves itself while alerting
  697.         do
  698.         {
  699.             // Tell the Printing Manager to display the selected alert
  700.  
  701.             anErr = GXAlertTheUser(pStatus);
  702.             if (anErr != noErr)
  703.                 break;
  704.             
  705.             // Remember the last printer problem we experienced
  706.             oldProblem = printerProblem;
  707.  
  708.             if (pStatus->dialogResult == 0)    //    T => No user button action yet
  709.             {
  710.                             
  711.                 // Pause before doing a status again.  If we status too often,
  712.                 // the printer gets a bit upset at us.
  713.                 WaitForABit();
  714.                 
  715.                 // Check to see if the printer problem has gone away or is now a different problem
  716.                 anErr = CheckPrinter(pStatus, &printerProblem, &abortPrinting);
  717.                 if (anErr != noErr)
  718.                     break;
  719.             
  720.                     
  721.                 // If we've now experienced a fatal printer problem (e.g. bad hardware) that is different
  722.                 // than the original problem, then alert the user to the problem.
  723.                 
  724.                 if ( abortPrinting && (oldProblem != printerProblem) )
  725.                 {
  726.                     // Make sure the previous alert has been dismissed by the Printing Finder Extension
  727.                     
  728.                     anErr = ClearStatus(pStatus);
  729.                     require(anErr == noErr, ClearStatus1);
  730.  
  731.                     // Initialize the status record's statResID and statResIndex fields based upon the abort error
  732.                     SetStatusIndex(pStatus, printerProblem, manualFeed, false);
  733.                     
  734.                     // Initialize the contents of the status record buffer based upon the abort error
  735.                     SetStatusBuffer(pStatus, printerProblem, manualFeed, thePaperType);
  736.         
  737.                     // Make sure the dialogResult has been reset from the previously displayed dialog
  738.                     pStatus->dialogResult = 0;
  739.         
  740.                     // Display the new fatal error alert until the user acknowledges it
  741.                     do
  742.                     {
  743.                         anErr = GXAlertTheUser(pStatus);
  744.                     }
  745.                     while ( (pStatus->dialogResult == 0) && (anErr == noErr) );
  746.                 }
  747.                 // else - not a fatal error or the printer problem hasn't changed
  748.             }
  749.             // else - user hasn't clicked any button yet
  750.         }
  751.         while ((pStatus->dialogResult == 0) && (oldProblem == printerProblem) && (anErr == noErr) );
  752.  
  753.         // At this point there has been some resolution to the problem.  The user responded to the
  754.         // alert, the printer problem was fixed at the printer, we got an error checking the status
  755.         // of the printer, or we got an error trying to alert the user. We must always clear status 
  756.         // to make sure that the alert is dismissed.  Then check for errors.
  757.  
  758.         anErr2 = ClearStatus(pStatus);
  759.         if (anErr2 != noErr)
  760.         {
  761.             if (anErr == noErr)
  762.                 anErr = anErr2;
  763.             require(anErr2 == noErr, ClearStatus2);
  764.         }
  765.         
  766.         // If the user has cancelled printing, set the user abort error
  767.         if (pStatus->dialogResult == cancel)
  768.         {
  769.             anErr = gxPrUserAbortErr;
  770.             require(anErr == noErr, UserAborted);
  771.         }
  772.  
  773.         // Did we have a problem statusing the printer or alerting the user?
  774.         require(anErr == noErr, InitialAlertFails);
  775.         
  776.         // Was the original error we displayed a fatal printer problem?
  777.         require(!abortPrinting, PrinterDied);
  778.  
  779.         // If we are in manual feed mode and the user has decided to switch to automatic feed
  780.         // then we will exit.  The problem has basically gone away and we'll catch any new problems
  781.         // when the calling routine re-checks to make sure the printer is ready.
  782.  
  783.         if (    (manualFeed) &&
  784.                 (GetStatResIndex(printerProblem) == kOutOfPaperStatIdx) && 
  785.                 (pStatus->dialogResult == gxAutoFeedButtonId)
  786.             )
  787.             printerProblem = kNoPrinterProblem;
  788.                 
  789.  
  790.         // If the user has dismissed the alert but the same problem still remains, we sit 
  791.         // in a loop until either the printer problem is resolved or another problem arises.  Here 
  792.         // the status record passed to AlertTheUser is guaranteed to not generate alerts, because
  793.         // the 'stat' item referenced is not of type userAttention or userAlert.  
  794.  
  795.         if ((printerProblem != kNoPrinterProblem) && (oldProblem == printerProblem))
  796.         {
  797.             // Initialize the status record's statResID and statResIndex fields based upon the abort error
  798.             SetStatusIndex(pStatus, printerProblem, manualFeed, true);
  799.             
  800.             // Update the PFE with the new status
  801.             
  802.             anErr = GXAlertTheUser(pStatus);
  803.             require(anErr == noErr, AlertTheUser);
  804.  
  805.             // Keep statusing the printer until the problem is fixed or the problem changes
  806.             do
  807.             {
  808.                 // Pause before doing a status again.  If we status too often,
  809.                 // the printer gets a bit upset at us.
  810.                 WaitForABit();
  811.  
  812.                 anErr = CheckPrinter(pStatus, &printerProblem, &abortPrinting);
  813.                 require(anErr == noErr, CheckPrinter);
  814.  
  815.                 // Let the client app have a chance to run
  816.                 anErr = GXJobIdle();
  817.                 require(anErr == noErr, JobIdleFails);
  818.             }
  819.             while ( (printerProblem != kNoPrinterProblem) && (oldProblem == printerProblem) );
  820.         }
  821.         // else - no longer a printer problem or now it's a different problem
  822.     }
  823.     while (printerProblem != kNoPrinterProblem);
  824.  
  825.     // Make sure the result of displaying the alert is returned
  826.     *dialogResult = pStatus->dialogResult;
  827.  
  828.  
  829. /******* Clean-up *******/
  830.  
  831. JobIdleFails:
  832. CheckPrinter:
  833. AlertTheUser:
  834. InitialAlertFails:
  835. UserAborted:
  836. ClearStatus2:
  837. ClearStatus1:
  838.     DisposPtr((Ptr) pStatus);
  839.     
  840. NewPtrClear:
  841. NoPrinterProblem:
  842.     return(anErr);
  843.     
  844. PrinterDied:
  845.     DisposPtr((Ptr) pStatus);
  846.     return(gxPrIOAbortErr);
  847. }
  848. /* ResolvePrinterProblem */
  849.  
  850.